﻿using BSF.BaseService.NScript.Compiler;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace BSF.BaseService.NScript.Core
{
    public class DynamicCompilerProvider
    {

        public Assembly Compiler(CompilerInfo compilerInfo)
        {
           
            Assembly objAssembly = null;

            // 1.CodeDomProvider
            CodeDomProvider objICodeCompiler = CodeDomProvider.CreateProvider(compilerInfo.EnumCompilerLanguage.ToString());

            // 2.CompilerParameters
            CompilerParameters objCompilerParameters = new CompilerParameters();
            objCompilerParameters.ReferencedAssemblies.AddRange(Config.SystemReferencedAssembliesDlls.ToArray());
            foreach (var r in compilerInfo.DllFiles)
            {
                if (!objCompilerParameters.ReferencedAssemblies.Contains(r.FullFileName))
                    objCompilerParameters.ReferencedAssemblies.Add(r.FullFileName);
            }
          
            objCompilerParameters.GenerateExecutable = false;
            objCompilerParameters.GenerateInMemory = true;

            if (compilerInfo.EnumCompilerMode == EnumCompilerMode.Main)
            {
                objCompilerParameters.GenerateExecutable = true;
                objCompilerParameters.GenerateInMemory = false;
            }

            //objCompilerParameters.GenerateInMemory = false;
            //objCompilerParameters.CompilerOptions = "/target:library /optimize";
            //objCompilerParameters.OutputAssembly = @"C:\Users\cjy\Desktop\test\" + DateTime.Now.ToString("yymmddHHmmss") + ".dll";
            

            // 3.CompilerResults
            CompilerResults cr = null;
            List<string> codes = new List<string>();
            //文件编译
            if (compilerInfo.EnumSourceType== EnumSourceType.File)
            {
                codes.Add(compilerInfo.MainFilePath.FullFileName);
                foreach (var file in compilerInfo.CodeFilePaths)
                {
                    codes.Add(file.FullFileName);
                }
                cr = objICodeCompiler.CompileAssemblyFromFile(objCompilerParameters, codes.ToArray());
            }
            //内容编译
            else if (compilerInfo.EnumSourceType == EnumSourceType.Code)
            {
                codes.Add(compilerInfo.MainFileContent);
                foreach (var file in compilerInfo.CodeFilePaths)
                {
                    codes.Add(System.IO.File.ReadAllText(file.FullFileName));
                }
                cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, codes.ToArray());
            }
          

            if (cr.Errors.HasErrors)
            {
                string errors = "";
                foreach (CompilerError err in cr.Errors)
                {
                    errors += string.Format("错误:{0},行号:{1},列号:{2},文件名:{3}\n", err.ErrorText, err.Line,err.Column, err.FileName);
                }
                if (!string.IsNullOrWhiteSpace(errors))
                {
                    throw new NScriptException("编译错误信息:" + errors);
                }
            }
            else
            {
                objAssembly = cr.CompiledAssembly;
                LoadReferencedAssembliesFile(compilerInfo);
            }
            return objAssembly;

        }



        public void LoadReferencedAssembliesFile(CompilerInfo compilerInfo)
        {
            string systemdir = System.IO.Path.GetDirectoryName(typeof(string).Assembly.Location).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
            foreach (var dll in compilerInfo.DllFiles)
            {
                string filepath = "";
                //默认系统自带文件
                if (System.IO.File.Exists(systemdir + dll.FileName))
                {
                    filepath = systemdir + dll.FileName;
                    continue;
                }
                //默认系统编译文件
                if (Config.SystemReferencedAssembliesDlls.Contains(dll.FileName))
                {
                    continue;
                }
                   
                //加载程序集文件
                if (System.IO.File.Exists(dll.FullFileName))
                {
                    filepath = dll.FullFileName;

                    var find = (from o in AppDomain.CurrentDomain.GetAssemblies() where o.GetName().Name.ToLower() == System.IO.Path.GetFileNameWithoutExtension(dll.FileName.ToLower()) select o).FirstOrDefault();
                    if (find == null)
                    {
                        try
                        {
                            Assembly.LoadFrom(filepath);
                        }
                        catch (Exception exp)
                        {
                            throw new NScriptException("Assembly.LoadFrom" + dll.FileName + "出错");
                        }
                    }
                  
                }

                
                
            }
        }
    }
}
